---
title: "03-Java 构造方法详解"
aliases:
- "Java 构造方法详解"
created: 2025-12-25
---
# Java 构造方法详解
---
## 一、构造方法概述
### **1.1 什么是构造方法**
```drawio
```
### **1.2 基本语法**
```
[访问修饰符] 类名(参数列表) {
// 初始化代码
}
```
```java
public class Student {
private String name;
private int age;
// 构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
// 使用
Student stu = new Student("张三", 20);
```
### **1.3 构造方法 vs 普通方法**
| **对比项** | **构造方法** | **普通方法** |
| --- | --- | --- |
| **命名** | 必须与类名相同 | 任意合法标识符 |
| **返回值** | 无(连 void 都没有) | 必须声明返回类型 |
| **调用时机** | new 时自动调用 | 手动调用 |
| **调用次数** | 每个对象只调用一次 | 可多次调用 |
| **作用** | 初始化对象 | 执行功能 |
| **继承** | 不能被继承 | 可以被继承 |
| **重写** | 不能重写 | 可以重写 |
---
## 二、默认构造方法
### **2.1 编译器自动生成**
```drawio
```
#### **代码示例**
```java
// 源代码(没有写构造方法)
public class Product {
private String name;
private double price;
}
// 编译后等价于(编译器自动添加)
public class Product {
private String name;
private double price;
// 编译器添加的默认构造方法
public Product() {
// 空实现
}
}
```
```
// 可以正常使用无参构造
Product p = new Product(); // ✅ 正确
```
### **2.2 查看字节码验证**
```
# 编译
javac Product.java
# 查看字节码
javap -c Product.class
```
**输出结果**:
```java
public class Product {
public Product(); // ← 编译器生成的默认构造方法
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
}
```
### **2.3 默认构造方法的特点**
| **特点** | **说明** |
| --- | --- |
| 访问修饰符 | 与类的访问修饰符相同 |
| 参数 | 无参数 |
| 方法体 | 空(仅调用父类无参构造) |
| 生成条件 | 类中没有任何显式构造方法 |
```java
// 类是 public,默认构造也是 public
public class A {
}
// 类是默认访问权限,默认构造也是默认权限
class B {
}
```
---
## 三、手动定义构造方法
### **3.1 ⚠️ 重要规则**
```drawio
```
### **3.2 错误示例**
```java
public class Product {
private String name;
// 手动定义了有参构造
public Product(String name) {
this.name = name;
}
}
// 使用
public class Main {
public static void main(String[] args) {
Product p1 = new Product("手机"); // ✅ 正确
Product p2 = new Product(); // ❌ 编译错误!
}
}
```
**编译错误信息**:
```yaml
Error: java: 无法将类 Product 中的构造器 Product 应用到给定类型
需要: java.lang.String
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
```
### **3.3 解决方案:显式定义无参构造**
```java
public class Product {
private String name;
// ✅ 显式定义无参构造
public Product() {
this.name = "未命名商品";
}
// 有参构造
public Product(String name) {
this.name = name;
}
}
// 现在都可以使用
Product p1 = new Product(); // ✅ 调用无参构造
Product p2 = new Product("手机"); // ✅ 调用有参构造
```
### **3.4 流程图:默认构造的生成逻辑**
```drawio
```
---
## 四、构造方法重载
### **4.1 什么是构造方法重载**
```drawio
```
### **4.2 代码示例**
```java
public class Student {
private String name;
private int age;
private String school;
// 构造方法 1:无参
public Student() {
this.name = "未知";
this.age = 0;
this.school = "未知";
}
// 构造方法 2:一个参数
public Student(String name) {
this.name = name;
this.age = 0;
this.school = "未知";
}
// 构造方法 3:两个参数
public Student(String name, int age) {
this.name = name;
this.age = age;
this.school = "未知";
}
// 构造方法 4:三个参数(全参构造)
public Student(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
}
}
```
```
// 多种创建方式
Student s1 = new Student(); // 调用构造1
Student s2 = new Student("张三"); // 调用构造2
Student s3 = new Student("李四", 20); // 调用构造3
Student s4 = new Student("王五", 21, "清华大学"); // 调用构造4
```
### **4.3 使用 this() 调用其他构造方法**
```java
public class Student {
private String name;
private int age;
private String school;
// 全参构造(主构造方法)
public Student(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
System.out.println("创建学生:" + name);
}
// 无参构造 → 调用全参构造
public Student() {
this("未知", 0, "未知"); // ✅ 调用全参构造
}
// 一参构造 → 调用全参构造
public Student(String name) {
this(name, 0, "未知"); // ✅ 调用全参构造
}
// 两参构造 → 调用全参构造
public Student(String name, int age) {
this(name, age, "未知"); // ✅ 调用全参构造
}
}
```
**调用链示**意图:
```drawio
```
### **4.4 this() 使用规则**
| **规则** | **说明** |
| --- | --- |
| 必须在第一行 | `this()` 必须是构造方法的第一条语句 |
| 只能调用一次 | 一个构造方法中只能有一个 `this()` |
| 不能循环调用 | A 调 B,B 不能再调 A |
| 不能和 super() 共存 | 二者都要求在第一行 |
```java
// ❌ 错误示例
public Student() {
System.out.println("准备创建"); // 错误!this() 必须在第一行
this("默认");
}
// ❌ 错误示例:循环调用
public Student() {
this("默认"); // 调用一参构造
}
public Student(String name) {
this(); // 又调用无参构造 → 死循环!编译器报错
}
```
---
## 五、构造方法的特点总结
### **5.1 五大特点一览表**
| **序号** | **特点** | **说明** | **示例** |
| --- | --- | --- | --- |
| 1️⃣ | 方法名与类名相同 | 严格一致,包括大小写 | `class Dog { Dog() {} }` |
| 2️⃣ | 没有返回值类型 | 连 void 都不写 | `public Student() {}` |
| 3️⃣ | 自动调用 | new 时自动执行 | `new Student()` |
| 4️⃣ | 可以重载 | 多个构造,参数不同 | 见上文示例 |
| 5️⃣ | 不能被修饰 | 不能用 static/final/abstract | — |
---
### **5.2 特点详解图**
```drawio
```
### **5.3 易混淆点:构造方法 vs 同名普通方法**
```java
public class Demo {
// ✅ 这是构造方法(无返回类型)
public Demo() {
System.out.println("构造方法执行");
}
// ⚠️ 这是普通方法!(有返回类型 void)
public void Demo() {
System.out.println("普通方法执行");
}
}
public class Main {
public static void main(String[] args) {
Demo d = new Demo(); // 输出:构造方法执行
d.Demo(); // 输出:普通方法执行
}
}
```
> *⚠️ **注意**:虽然语法允许定义与类名相同的普通方法,但这是极差的编码习惯!*
---
## 六、构造方法与继承
### **6.1 子类构造调用父类构造**
```drawio
```
### **6.2 代码示例**
```java
class Animal {
protected String name;
public Animal() {
System.out.println("Animal 无参构造");
}
public Animal(String name) {
this.name = name;
System.out.println("Animal 有参构造:" + name);
}
}
class Dog extends Animal {
private String breed;
// 隐式调用 super()
public Dog() {
// 编译器自动添加:super();
System.out.println("Dog 无参构造");
}
// 显式调用 super(name)
public Dog(String name, String breed) {
super(name); // ✅ 必须在第一行
this.breed = breed;
System.out.println("Dog 有参构造:" + breed);
}
}
```
```
// 测试
Dog d1 = new Dog();
// 输出:
// Animal 无参构造
// Dog 无参构造
Dog d2 = new Dog("旺财", "金毛");
// 输出:
// Animal 有参构造:旺财
// Dog 有参构造:金毛
```
### **6.3 构造方法调用顺序图**
```drawio
```
### **6.4 常见错误:父类没有无参构造**
```java
class Parent {
public Parent(String name) { // 只有有参构造
System.out.println("Parent: " + name);
}
}
class Child extends Parent {
public Child() {
// 编译器隐式添加 super(),但 Parent 没有无参构造!
// ❌ 编译错误!
}
}
```
**解决**方案:
```java
// 方案 1:子类显式调用父类有参构造
class Child extends Parent {
public Child() {
super("默认名称"); // ✅ 显式调用
}
}
// 方案 2:父类添加无参构造
class Parent {
public Parent() { } // ✅ 添加无参构造
public Parent(String name) {
System.out.println("Parent: " + name);
}
}
```
---
## 七、最佳实践
### **7.1 实践规则一览表**
| **序号** | **规则** | **原因** |
| --- | --- | --- |
| 1 | 始终保留无参构造 | 框架反射、序列化需要 |
| 2 | 使用 this() 避免重复 | 代码复用,统一初始化 |
| 3 | 参数校验放构造中 | 确保对象状态合法 |
| 4 | 避免调用可重写方法 | 防止子类未初始化完成 |
| 5 | 考虑使用建造者模式 | 参数过多时更清晰 |
---
### **7.2 实践 1:始终保留无参构造**
```java
public class User {
private String username;
private String email;
// ✅ 始终保留无参构造
public User() {
}
public User(String username, String email) {
this.username = username;
this.email = email;
}
}
```
**需要无参构造的场**景:
```drawio
```
### **7.3 实践 2:使用 this() 避免代码重复**
```java
// ❌ 不好的写法:重复代码
public class Product {
private String name;
private double price;
private String category;
public Product() {
this.name = "未命名";
this.price = 0.0;
this.category = "未分类";
validate(); // 重复
log(); // 重复
}
public Product(String name) {
this.name = name;
this.price = 0.0;
this.category = "未分类";
validate(); // 重复
log(); // 重复
}
public Product(String name, double price, String category) {
this.name = name;
this.price = price;
this.category = category;
validate(); // 重复
log(); // 重复
}
}
```
```java
// ✅ 好的写法:使用 this() 委托
public class Product {
private String name;
private double price;
private String category;
// 全参构造(核心构造方法)
public Product(String name, double price, String category) {
this.name = name;
this.price = price;
this.category = category;
validate(); // 只写一次
log(); // 只写一次
}
// 委托给全参构造
public Product() {
this("未命名", 0.0, "未分类");
}
public Product(String name) {
this(name, 0.0, "未分类");
}
public Product(String name, double price) {
this(name, price, "未分类");
}
}
```
### **7.4 实践 3:在构造方法中进行参数校验**
```java
public class BankAccount {
private String accountNumber;
private double balance;
public BankAccount(String accountNumber, double initialBalance) {
// ✅ 参数校验
if (accountNumber == null || accountNumber.trim().isEmpty()) {
throw new IllegalArgumentException("账号不能为空");
}
if (initialBalance < 0) {
throw new IllegalArgumentException("初始余额不能为负");
}
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
}
```
```
// 使用
BankAccount acc1 = new BankAccount("123456", 1000); // ✅ 正常
BankAccount acc2 = new BankAccount("", 100); // ❌ 抛出异常
BankAccount acc3 = new BankAccount("123", -100); // ❌ 抛出异常
```
### **7.5 实践 4:避免在构造方法中调用可重写方法**
```java
// ❌ 危险的写法
class Parent {
public Parent() {
init(); // 调用可重写方法
}
public void init() {
System.out.println("Parent init");
}
}
class Child extends Parent {
private String name;
public Child(String name) {
super(); // 调用父类构造
this.name = name;
}
@Override
public void init() {
// ⚠️ 此时 name 还是 null!因为子类构造还没执行完
System.out.println("Child init: " + name.toUpperCase()); // NullPointerException!
}
}
```
**问题分析**图:
```drawio
```
**解决方**案:
```java
// ✅ 使用 final 方法或 private 方法
class Parent {
public Parent() {
initInternal(); // 调用 private 方法
}
private void initInternal() { // 不能被重写
System.out.println("Parent init");
}
}
```
### **7.6 实践 5:参数过多时使用建造者模式**
```
// ❌ 构造参数过多,难以阅读
User user = new User("张三", 20, "男", "北京", "100000",
"13800138000", "zhangsan@email.com", true);
// ✅ 使用建造者模式
User user = User.builder()
.name("张三")
.age(20)
.gender("男")
.city("北京")
.build();
```
**建造者模式实**现:
```java
public class User {
private final String name;
private final int age;
private final String gender;
private final String city;
// 私有构造,只能通过 Builder 创建
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
this.city = builder.city;
}
// 静态方法获取 Builder
public static Builder builder() {
return new Builder();
}
// 静态内部类 Builder
public static class Builder {
private String name;
private int age;
private String gender;
private String city;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Builder city(String city) {
this.city = city;
return this;
}
public User build() {
return new User(this);
}
}
}
```
---
## 八、核心总结
### **8.1 知识要点速查表**
| **主题** | **要点** |
| --- | --- |
| **默认构造** | 没有任何构造方法时编译器自动生成 |
| **消失条件** | 定义任何构造方法后默认构造消失 |
| **重载** | 同类中多个构造,参数不同 |
| **this()** | 调用本类其他构造,必须在第一行 |
| **super()** | 调用父类构造,必须在第一行 |
| **执行顺序** | Object → 父类 → 子类 |
---
### **8.2 构造方法完整生命周期图**
```drawio
```
### **8.3 最佳实践清单**
```drawio
```